package cn.lixiaodan.hqlbuilder.packagescan;

import java.io.File;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import cn.lixiaodan.hqlbuilder.util.AppPrefs;

public class PackageScanner {
	public static final String BASE_PACKAGE = AppPrefs.getString("BASE_PACKAGE");
	private static String[] classPath;
	private static HashSet<String> CLASSE_2_FIND = new HashSet<String>();;

	public static HashSet<String> getAllClasses() {
		synchronized (CLASSE_2_FIND) {
			if (CLASSE_2_FIND.size() == 0) {
				new PackageScanner().scanClass();
			}
			return CLASSE_2_FIND;
		}
	}

	private static HashSet<String> scanClass() {
		synchronized (CLASSE_2_FIND) {
			if (classPath == null) {
				String classpath = System.getProperty("java.class.path");
				classPath = classpath.split(";");
			}
			for (int i = 0; classPath != null && i != classPath.length; i++) {
				File path = new File(classPath[i]);
				if (!path.exists())
					continue;
				if (path.isDirectory()) {
					listfile(path.getAbsolutePath(), path, CLASSE_2_FIND);
				} else if (path.isFile()) {
					listjar(path.getAbsolutePath(), path, CLASSE_2_FIND);
				}
			}
			return CLASSE_2_FIND;
		}
	}

	private static void listjar(String basepath, File jarpath, HashSet<String> cls2find) {
		try {
			ZipFile zfile = new ZipFile(jarpath);
			Enumeration zfiles = zfile.entries();
			while (zfiles.hasMoreElements()) {
				ZipEntry entry = (ZipEntry) zfiles.nextElement();
				String shortname = entry.getName();
				if (shortname.endsWith(".class")) {
					shortname = parseName(shortname);
					if (basepackFilter(shortname))
						cls2find.add(shortname);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private static void listfile(String basepath, File path, HashSet<String> cls2find) {
		if (!path.exists())
			return;
		if (path.isDirectory()) {
			File files[] = path.listFiles();
			for (int i = 0; i != files.length; i++) {
				listfile(basepath, files[i], cls2find);
			}
		} else {
			if (path.getName().endsWith(".class")) {
				String shortpath = path.getAbsolutePath().replace(basepath, "");
				shortpath = parseName(shortpath);
				if (basepackFilter(shortpath))
					cls2find.add(shortpath);
			}
		}
	}

	private static String parseName(String shortpath) {
		return shortpath.replaceAll("[\\\\\\/]", ".").replaceAll("(\\$\\d+)?\\.class$", "").replaceAll("^\\.", "");
	}

	private static boolean basepackFilter(String clsname) {
		return clsname.startsWith(BASE_PACKAGE);
	}
}
